#!/usr/bin/env python

#importing other parts of project
from Skeleton import GnomeAppletSkeleton
from SettingsManager import SettingsManager
from ConfClient import ConfClient

import sys

#module for XMPP protocol
import xmpp

#GUI modules
import gtk
import gnomeapplet
import gobject
import gconf

#module to show pop-up notifications
import pynotify

class BtXapplet(GnomeAppletSkeleton):
	"""Main applet class"""

	def init_ppmenu(self):
		"""Init popup menu"""
		self.applet.setup_menu("""
                <popup name="button3">
	                <menuitem name="About Item" verb="About" stockid="gtk-about" />	
			<menuitem name="Conf Item" verb="Preferencies" stockid="gtk-properties" />
			<menuitem name="Conn Item" verb="Connect" stockid="gtk-connect" />
			<menuitem name="Conn Item" verb="Disconnect" stockid="gtk-disconnect" />
                </popup>
               """, [("About", self.on_ppm_about),("Preferencies",self.on_ppm_preferencies),("Connect",self.xmpp_connect),("Disconnect",self.xmpp_disconnect),],None)
										
	def on_ppm_preferencies(self,event,data=None):
		"""Display settings window"""

#		create and display settings window
		sm = SettingsManager()
#		get settings from window
		self.user, self.passw, self.domain, self.sendto = sm.user, sm.passw, sm.domain, sm.sendto
		del sm
#		reconnect to server
		self.xmpp_disconnect()
		self.xmpp_connect()
		
	def after_init(self):
		"""Init some variables, load configuration and connect to server"""

#		callbacks to react to left button click on applet
		self.button_actions = {
			1: self.send_mess,
			2: lambda: None,
			3: lambda: None,
		}

#		init notification engine
		pynotify.init("BtX applet")
#		default look - disconnected
		self.set_visual_state("none", False)
#		load configuration
		cclient = ConfClient()
		if cclient.state:
#			if configuration file exists, load configuration
			self.user, self.passw, self.domain, self.sendto = cclient.load_conf()
		else:
#			if not, initialize variables with 'None'
			self.user, self.passw, self.domain, self.sendto = None, None, None, None
		self.xmpp_connect()

	def init_additional_widgets(self):
		"""Create additional widgets"""
#		load images to show in panel
		self._init_pixbufs()
		self.image = gtk.Image()
		self.ev_box.add(self.image)

	def _init_pixbufs(self):
		"""Init pixbufs from current theme, or from Tango, if 'im-jabber' icon not in current theme"""
		self.pixbufs = {}
		self.theme = self._get_theme()
		try:
			self._reload_pixbufs()
		except gobject.GError:
			self.theme = self._get_theme('Tango')
			self._reload_pixbufs()

	def _get_theme(self, name=None):
		"""Return a theme by name, or current one if name is None"""
		if name is None:
			name = gconf.client_get_default().get_string('/desktop/gnome/interface/icon_theme')
		theme = gtk.IconTheme()
		theme.set_custom_theme(name)
		return theme

	def _reload_pixbufs(self, size=None):
		"""Reload pixbufs from current theme for specified size, or for panel's size if size is None"""
		if size is None:
			size = self.applet.get_size()
		pixbuf = self.theme.load_icon('im-jabber', size, gtk.ICON_LOOKUP_FORCE_SVG)
		faded_pixbuf = gtk.gdk.Pixbuf(pixbuf.get_colorspace(),
			pixbuf.get_has_alpha(),
			pixbuf.get_bits_per_sample(),
			pixbuf.get_width(),
			pixbuf.get_height()) 
		pixbuf.saturate_and_pixelate(faded_pixbuf, 1, True)
		self.pixbufs[True] = pixbuf
		self.pixbufs[False] = faded_pixbuf
	
	def set_visual_state(self, user, is_on):
		"""
		Change state of applet icon in gnome panel
		
		Parameters:
		user: Name of currently connected user
		
		is_on: Flag, indicating, whether applet is connected to XMPP server or not
		"""
#		message displayed when connected
		msg_on_state = "Client connected"
#		message when not connected
		msg_off_state = "Client not connected"
#		name of connected user
		acc = "Account: %s" % user
#		choose correct tooltip
		variant = (is_on and msg_on_state) or msg_off_state
#		update tooltip
		self.info = "%s (%s)" % (variant, acc)
#		update image
		self._set_image(is_on)
	
	def _set_image(self, kind):
		"""Sets current image
		
		Parameters:
		
		kind: when true, uses normal picture, when false, uses faded picture
		"""
		self.image.set_from_pixbuf(self.pixbufs[kind])
	
	def on_tooltip(self, widget, x, y, keyboard_mode, tooltip):
		"""Updates a tooltip when mouse is over applet"""
#		display connection state
		tooltip.set_icon_from_icon_name("im-jabber",self.applet.get_size())
		tooltip.set_text(self.info)
		return True

	def xmpp_connect(self,widget=None,event=None):
		"""Connects to a server"""
		if (self.user is None or self.passw is None or self.domain is None):
#			not configured
			pynotify.Notification("BtX: can`t start","No settings, waiting for set up...","stock_dialog-warning").show()
			return
		
#		init XMPP client
		self.jid = xmpp.JID("%s@%s/" % (self.user, self.domain))

#		don`t display XMPP debug info in terminal
		self.bot = xmpp.Client(self.jid.getDomain(),debug=[])

		try:
#			try to connect
			self.bot.connect()
		except:
#			error while connecting
			pynotify.Notification("BtX: can`t connect","Error while trying to connect to server.\nAborting...","stock_dialog-error").show()
			try:
				self.bot.disconnected()
			except IOError:
				pass

			del self.bot
			self.bot = None
			return

		try:
			if self.bot.auth(self.jid.getNode(),self.passw) is None:
#				wrong password or username
				pynotify.Notification("BtX: can`t auth","Cannot authenticate, check your password","stock_dialog-error").show()
				del self.bot
				self.bot = None
				return
		except:
#			not connected (somewhy exception is here, but i expected it to be after self.bot.connect)
			pynotify.Notification("BtX: can`t connect","Error while trying to connect to server.\nAborting...","stock_dialog-error").show()
			try:
				self.bot.disconnected()
			except IOError:
				pass

			del self.bot
			self.bot = None
			return

#		notify good connection
		pynotify.Notification("BtX: connected","Succesfully connected to server %s as user %s" % (self.domain, self.user),"connect_established").show()
		self.set_visual_state("%s@%s" % (self.user, self.domain),True)

	def xmpp_disconnect(self,widget=None,event=None):
		"""Disconnects from server"""

#		if not connected, do nothing
		if self.bot == None:
			return

		try:
			self.bot.disconnected()
		except IOError:
			pass

		del self.bot
		self.bot = None
		pynotify.Notification("BtX: disconnected","Succesfully disconnected from server %s" % self.domain,"connect_no").show()
		self.set_visual_state("none",False)
	
	def xmpp_disconnected(self):
		"""Called by self.bot on disconnection"""
		del self.bot
		self.bot = None
		pynotify.Notification("BtX: disconnected","Server aborted connection or network is down","stock_dialog-error").show()
		self.set_visual_state("none",False)

	def send_mess(self):
		"""Sends message with text from clipboard"""
		if self.bot is not None:
#			get message text from clipboard
			mess = self._get_text_from_clipboard()
#			let reciever know that this was sent automatically
			self.bot.send(xmpp.Message(
						self.sendto,
						"%s\n%s\n%s" %
						("===	THIS WAS SENT AUTOMATICALLY BY BOT	===",
						mess,
						"===	END OF AUTOMATICALLY GENERATED MESSAGE	===",)
						))
#			connected, notify success
			pynotify.Notification("BtX: sent","Succesfully sent message to %s from %s@%s\n\nMessage:\n%s" % (self.sendto, self.user, self.domain, mess),"im-jabber").show()
		else:
#			not connected, display error
			pynotify.Notification("BtX: can`t send","Can`t send message when not connected","stock_dialog-error").show()
	
	def _get_text_from_clipboard(self):
		"""Extracts text from cliboard"""
		clipboard=gtk.Clipboard(display=gtk.gdk.display_get_default(), selection="CLIPBOARD")
		text=clipboard.wait_for_text()
		clipboard.store()    

		return text

	def on_ppm_about(self, event, data=None):
		"""Action on choosing 'about' in popup menu"""
#		show gnome standart about dialog
		about = gtk.AboutDialog()
#		set program name
		about.set_name("Bash to XMPP transmitter applet")
#		set program version
		about.set_version("0.1")
#		set copyrights
		about.set_copyright("Maxim Koltsov <kolmax94@gmail.com>")
#		set program info
		about.set_comments("Send good quotes from bash.org to your friend via XMPP protocol")
#		set license (GNU GPLv2)
		about.set_license("""
Bash to XMPP transmitter applet - Send good quotes from bash.org to your friend via XMPP protocol
Copyright (C) 2010  Koltsov Maxim

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
		""")
#		set program website
		about.set_website("http://btx-applet.googlecode.com")
#		set program authors
		about.set_authors(["Maxim Koltsov <kolmax94@gmail.com>","Pythy <the.pythy@gmail.com.>",])
#		set program logo (default logo of jabber)
		about.set_logo_icon_name("im-jabber")
#		run about dialog
		about.run()
#		correctly destroy object
		about.destroy()
		del about

def applet_factory(applet, iid):
	"""Factory for starting applet with bonobo"""
	BtXapplet(applet, iid)
	return True


def run_in_window():
	"""Special function to run applet in debugging windowed mode"""
#	create window for debugging
	main_window = gtk.Window(gtk.WINDOW_TOPLEVEL)
	main_window.set_title("BashToXMPP applet[debug mode]")
	main_window.connect("destroy", gtk.main_quit)
	app = gnomeapplet.Applet()
	applet_factory(app, None)
	app.reparent(main_window)
	main_window.show_all()
	gtk.main()
	sys.exit()

def run_in_panel():
	"""Run applet by bonobo factory"""
	gnomeapplet.bonobo_factory("OAFIID:GNOME_BtXapplet_Factory",BtXapplet.__gtype__,"BashToXMPP Applet","0.1",applet_factory)

def main(args):
	"""Determines how to start apllet and start it"""
	if len(args) == 2 and args[1] == "run-in-window":
		run_in_window()
	else:
		run_in_panel()

if __name__ == '__main__':
	main(sys.argv)
